import os
import threading
import time
import uuid
from typing import Dict, List, Optional, Callable


class HumanAssistanceManager:
  _instance = None
  _lock = threading.Lock()

  def __new__(cls):
    with cls._lock:
      if cls._instance is None:
        cls._instance = super().__new__(cls)
        cls._instance._init()
    return cls._instance

  def _init(self):
    self._requests: Dict[str, Dict] = {}
    self._requests_lock = threading.Lock()
    timeout_env = os.getenv("HUMAN_ASSISTANCE_TIMEOUT", "").strip()
    default_timeout = 30  # seconds
    if not timeout_env:
      self._timeout = default_timeout
    else:
      try:
        timeout_value = int(timeout_env)
        self._timeout = timeout_value if timeout_value > 0 else None
      except ValueError:
        self._timeout = default_timeout

  def request_help(self, prompt: str, context: str = "", artifact: str = "",
                   on_request: Optional[Callable[[Dict], None]] = None) -> Dict:
    request_id = str(uuid.uuid4())
    event = threading.Event()
    created_at = time.time()
    request = {
      "id": request_id,
      "prompt": prompt,
      "context": context,
      "artifact": artifact,
      "created_at": created_at,
      "event": event,
      "response": None,
      "responded_at": None,
      "status": "pending",
    }
    with self._requests_lock:
      self._requests[request_id] = request

    if on_request:
      try:
        on_request(request)
      except Exception:
        pass

    print(f"[Human Assistance] Request {request_id} created. Prompt: {prompt}")
    wait_timeout = self._timeout
    event.wait(wait_timeout)

    with self._requests_lock:
      stored = self._requests.pop(request_id, request)

    if stored.get("response") is None:
      stored["status"] = "timeout" if wait_timeout is not None else "cancelled"
      return {
        "status": stored["status"],
        "request_id": request_id,
        "message": "No human response received within timeout." if wait_timeout else "No human response received."
      }

    stored["status"] = "answered"
    return {
      "status": "answered",
      "request_id": request_id,
      "content": stored["response"],
      "responded_at": stored["responded_at"],
    }

  def list_pending_requests(self) -> List[Dict]:
    with self._requests_lock:
      pending = [
        {
          "requestId": req_id,
          "prompt": data["prompt"],
          "context": data["context"],
          "artifact": data["artifact"],
          "createdAt": data["created_at"],
        }
        for req_id, data in self._requests.items()
        if data["status"] == "pending"
      ]
    return pending

  def submit_response(self, request_id: str, content: str) -> Dict:
    with self._requests_lock:
      request = self._requests.get(request_id)
      if not request:
        raise ValueError(f"Request {request_id} not found or already handled.")
      request["response"] = content
      request["responded_at"] = time.time()
      request["status"] = "answered"
      request["event"].set()
      return {
        "requestId": request_id,
        "prompt": request["prompt"],
        "content": content,
      }


def get_human_assistance_manager() -> HumanAssistanceManager:
  return HumanAssistanceManager()
